package com.zx.znav.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.UUID;
import com.zx.znav.bean.User;
import com.zx.znav.bean.UserDescription;
import com.zx.znav.constant.Constants;
import com.zx.znav.constant.RedisConstants;
import com.zx.znav.controller.vo.UserVO;
import com.zx.znav.error.BusinessException;
import com.zx.znav.error.EnumBusinessError;
import com.zx.znav.response.CommonReturnType;
import com.zx.znav.service.EMailService;
import com.zx.znav.service.UserDescriptionService;
import com.zx.znav.service.UserService;
import com.zx.znav.utils.MD5Utils;
import com.zx.znav.utils.RegexUtils;
import com.zx.znav.utils.UserHolder;
import com.zx.znav.utils.ValidateCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author 挚爱之夕
 * @version 1.0
 * @implSpec 用户相关控制器。登录/注册
 * @since 2023-08-07 16:58
 */
@Controller
@RequestMapping("/user")
@Slf4j
public class UserController {
    @Autowired
    private UserService userService;
    @Autowired
    private EMailService eMailService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private UserDescriptionService userDescriptionService;

    /**
     * 发送验证码
     */
    @PostMapping("/sendMsg")
    @ResponseBody
    public Object sendMessage(User user) throws BusinessException {
        String email = user.getEmail();
        //验证邮箱
        if (!RegexUtils.isEmailValid(email)) {
            throw new BusinessException(EnumBusinessError.EMAIL_VALIDATION_ERROR);
        }
        //发送验证码
        String subject = "挚夕导航登录验证码";
        String code = ValidateCodeUtils.generateValidateCode(6);
        String context = "欢迎使用挚夕导航，登录验证码为: " + code + ",五分钟内有效，请妥善保管!";
        log.info("code={}", code);
        log.info("send={}", context);
        // 真正地发送邮箱验证码
        eMailService.sendMessage(email, subject, context);
        //缓存到Redis中，并且设置验证码的有效时间为 5分钟
        stringRedisTemplate.opsForValue().set(RedisConstants.EMAIL_CODE_KEY + email, code, RedisConstants.EMAIL_CODE_TTL, TimeUnit.MINUTES);
        return CommonReturnType.create("验证码发送成功,请注意查收!");
    }

    /**
     * 注册
     */
    @PostMapping("/register")
    @ResponseBody
    public Object register(User user, String code) throws BusinessException {
        //验证邮箱
        if (!RegexUtils.isEmailValid(user.getEmail())) {
            throw new BusinessException(EnumBusinessError.EMAIL_VALIDATION_ERROR);
        }
        //校验验证码
        String cacheCode = stringRedisTemplate.opsForValue().get(RedisConstants.EMAIL_CODE_KEY + user.getEmail());
        if (cacheCode == null || !Objects.equals(code, cacheCode)) {
            throw new BusinessException(EnumBusinessError.EMAIL_CODE_VALIDATION_ERROR);
        }
        //检查邮箱是否注册
        if (!userService.checkRegister(user.getEmail())) {
            throw new BusinessException(EnumBusinessError.EMAIL_EXIST);
        }
        //保存用户
        userService.saveUser(user);
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user, userVO);
        //生成token
        String token = UUID.randomUUID(true).toString();
        //缓存用户信息
        cacheUserByToken(userVO, token);
        //返回token
        return CommonReturnType.create(token);
    }

    //根据token,缓存用户信息
    private void cacheUserByToken(UserVO userVO, String token) {
        //StringRedisTemplate 每个字段都需要string,将字段属性转string
        Map<String, Object> userMap = BeanUtil.beanToMap(userVO, new HashMap<>(),
                CopyOptions.create()
                        .setIgnoreNullValue(true)
                        .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString())
        );
        //保存用户信息
        stringRedisTemplate.opsForHash().putAll(RedisConstants.LOGIN_USER_KEY + token, userMap);
        //设置过期时间
        stringRedisTemplate.expire(RedisConstants.LOGIN_USER_KEY + token, RedisConstants.LOGIN_USER_TTL, TimeUnit.MINUTES);
    }

    /**
     * 登录
     */
    @PostMapping("/login")
    @ResponseBody
    public Object login(User user) throws BusinessException {
        //加密
        String password = MD5Utils.code(user.getPassword());
        //登录校验
        User user1 = userService.checkLogin(user.getUsername(), password);
        if (user1 == null) {
            throw new BusinessException(EnumBusinessError.USER_LOGIN_FAIL);
        }
        //生成token
        String token = UUID.randomUUID(true).toString();
        //保存到redis
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user1, userVO);
        //缓存用户信息
        cacheUserByToken(userVO, token);
        //返回token
        return CommonReturnType.create(token);
    }

    /**
     * 根据token 获取用户信息，刷新用户头像及下拉列表
     */
    @GetMapping("/refreshNavbar")
    public String refreshAvatar(Model model) {
        model.addAttribute(Constants.MODEL_USER_KEY, UserHolder.getUser());
        return "fregments :: navbar";
    }

    /**
     * 登出
     */
    @PostMapping("/logout")
    @ResponseBody
    public Object logout(String token) {
        //清空缓存
        stringRedisTemplate.delete(RedisConstants.LOGIN_USER_KEY + token);
        return CommonReturnType.create("登出成功");
    }

    /**
     * 修改用户资料
     */
    @PutMapping("/updateInfo")
    @ResponseBody
    @Transactional
    public Object updateInfo(User user, String content, HttpServletRequest request) {
        //从请求头获取token
        String token = request.getHeader("authorization");
        if (user.getNickname() == null || user.getNickname().equals("")) {
            return CommonReturnType.create("昵称不能为空", CommonReturnType.FAIL);
        }
        if (content == null || content.equals("")) {
            return CommonReturnType.create("个人描述不能为空", CommonReturnType.FAIL);
        }
        //修改昵称
        User user1 = new User();
        user1.setId(UserHolder.getUser().getId());
        user1.setNickname(user.getNickname());
        userService.updateById(user1);
        //修改redis中的用户昵称
        UserVO userVO = UserHolder.getUser();
        userVO.setNickname(user.getNickname());
        cacheUserByToken(userVO, token);
        //个人描述
        UserDescription description = userDescriptionService.getDescriptionByUserId(UserHolder.getUser().getId());
        if (description == null) {
            //添加
            UserDescription userDescription = new UserDescription();
            userDescription.setUserId(UserHolder.getUser().getId());
            userDescription.setContent(content);
            userDescriptionService.save(userDescription);
        } else {
            //修改
            userDescriptionService.updateByUserId(UserHolder.getUser().getId(), content);
        }
        return CommonReturnType.create("修改成功");
    }

    /**
     * 修改密码
     */
    @PutMapping("/changePassword")
    @ResponseBody
    public Object change(String oldPassword, String newPassword) {
        UserVO userVO = UserHolder.getUser();
        User user = userService.getById(userVO.getId());
        oldPassword = MD5Utils.code(oldPassword);
        newPassword = MD5Utils.code(newPassword);
        if(user.getPassword().equals(oldPassword)){ //验证成功
            user.setPassword(newPassword);
            userService.updateById(user);
            return CommonReturnType.create("修改成功");
        }
        return CommonReturnType.create("密码不正确", CommonReturnType.FAIL);
    }
}
